/**
 * 为什么需要防抖和节流：在一些高频率事件触发的场景下我们不希望对应的事件处理函数多次执行
 * 使用场景：滚动事件、输入模糊匹配、轮播图切换、点击操作等
 * 浏览器默认情况下都会有自己的监听事件间隔（4ms-6ms），如果检测到多次事件的监听执行，那么就会造成不必要的资源浪费
 * 
 * 模拟前置的场景：界面上有一个按钮，我们可以连续多次点击
 * 防抖：对于这个高频的操作来说，我们只希望识别一次点击，可以是人为的第一次或者是最后一次
 * 节流：对于高频操作，我们可以自己来设置频率，让本来会执行很多次的事件触发，按着我们定义的频率减少触发的次数
 */

/**
 * 防抖函数
 *
 * @param {*} handle 执行的事件
 * @param {*} wait 执行间隔事件
 * @param {*} immediate 是否立即执行
 */
function debounce(handle, wait, immediate) {
  if (typeof handle !== 'function') throw new Error('handle must be an function')
  if (typeof wait === 'undefined') wait =300
  if (typeof wait === 'boolean') {
    immediate = wait
    wait = 300
  }
  if (typeof immediate !== 'boolean') immediate = false
  let timer = null
  return function proxy(...args) {
    const self = this
    const init = immediate && !timer
    clearTimeout(timer)
    timer = setTimeout(() => {
      timer = null
      !immediate ? handle.call(self, ...args) : null
    }, wait);
    // 当传进来immediate为true，立即执行
    init ? handle.call(self, ...args) : null
  }
}

/**
 * 节流函数
 *
 * @param {*} handle 执行的事件
 * @param {*} wait 执行间隔事件
 */
function throttle(handle, wait) {
  if (typeof handle !== 'function') throw new Error('handle must be an function')
  if (typeof wait === 'undefined') wait =500
  let pre = 0
  let timer = null
  return function proxy(...args) {
    const now = new Date()
    const self = this
    const interval = wait - (now - pre)
    if (interval <= 0) {
      clearTimeout(timer)
      timer = null
      handle.call(self, ...args)
      pre = new Date()
    } else if (!timer) {
      timer = setTimeout(() => {
        clearTimeout(timer)
        timer = null
        handle.call(self, ...args)
        pre = new Date()
      }, interval);
    }
  }
}